/*
 * main.c
 *
 *  Created on: 06/07/2012
 *      Author: annibal
 */

#include <stdio.h>
#include <string.h>
#include "ape.h"
#include "lexer.h"
#include "leitura.h"

/* Função para imprimir a configuração de um AF */
void imprimeAF(FILE *saida, Automato *M) {
	int i, j;

	fprintf(saida, "Estados: ");
	for (i = 0; i < M->numEstados; i++) {
		fprintf(saida, "%s ", M->estados[i].nome);
	}

	fprintf(saida, "\n\nAlfabeto: ");
	for (i = 0; i < M->tamAlfabeto; i++) {
		fprintf(saida, "%c ", M->alfabeto[i]);
	}

	fprintf(saida, "\n\nEstados finais: ");
	for (i = 0; i < M->numEstados; i++) {
		if (M->estados[i].final == 1) {
			fprintf(saida, "%s ", M->estados[i].nome);
		}
	}

	fprintf(saida, "\n\nEstado inicial: %s", M->estadoInicial->nome);

	fprintf(saida, "\n\nTransicoes:\n\n");

	fprintf(saida, "%8s", "");
	for (i = 0; i < M->tamAlfabeto; i++) {
		fprintf(saida, "%8c", M->alfabeto[i]);
	}
	fprintf(saida, "%8s\n", "outros");

	for (i = 0; i < M->numEstados; i++) {
		fprintf(saida, "%8s", M->estados[i].nome);

		for (j = 0; j <= M->tamAlfabeto; j++) {
			fprintf(saida, "%8s", M->transicoes[i][j]->nome);
		}
		fprintf(saida, "\n");
	}
}

void imprimeLexer(FILE *saida, Lexer *L) {
	int i;

	fprintf(saida, "Tokens: ");
	for (i = 0; i < L->numTokens; i++) {
		fprintf(saida, "%c ", L->listaTokens[i]);
	}
	fprintf(saida, "\n\n");

	imprimeAF(saida, L->AF);
}

/* Função para imprimir a configuração de um AF */
void imprimeAPE(FILE *saida, APE *M) {
	int i, j, k;
	Submaquina *a;

	fprintf(saida, "Alfabeto: ");
	for (i = 0; i < M->tamAlfabeto; i++) {
		fprintf(saida, "%c ", M->alfabeto[i]);
	}

	fprintf(saida, "\n\n");

	for (k = 0; k < M->numeroSubmaquinas; k++) {
		a = M->submaquinas + k;

		fprintf(saida, "Submáquina %c:\n\n", a->nome);

		fprintf(saida, "Estados: ");
		for (i = 0; i < a->AF.numEstados; i++) {
			fprintf(saida, "%s ", a->AF.estados[i].nome);
		}

		fprintf(saida, "\n\nEstados finais: ");
		for (i = 0; i < a->AF.numEstados; i++) {
			if (a->AF.estados[i].final == 1) {
				fprintf(saida, "%s ", a->AF.estados[i].nome);
			}
		}

		fprintf(saida, "\n\nEstado inicial: %s", a->AF.estadoInicial->nome);

		fprintf(saida, "\n\nTransicoes:\n\n");

		fprintf(saida, "%8s", "");
		for (i = 0; i < M->tamAlfabeto; i++) {
			fprintf(saida, "%8c", M->alfabeto[i]);
		}

		for (i = 0; i < M->numeroSubmaquinas; i++) {
			fprintf(saida, "%8c", M->submaquinas[i].nome);
		}

		fprintf(saida, "\n");

		for (i = 0; i < a->AF.numEstados; i++) {
			fprintf(saida, "%8s", a->AF.estados[i].nome);

			for (j = 0; j < M->tamAlfabeto + M->numeroSubmaquinas; j++) {
				fprintf(saida, "%8s", a->AF.transicoes[i][j]->nome);
			}
			fprintf(saida, "\n");
		}
		fprintf(saida, "\n");
	}
}

/* Função para abertura de arquivos */
FILE *abreArquivo(char *modo) {
	char nome_arq[TAM_STRING];
	FILE *arq;

	do {
		gets(nome_arq);
	} while (strlen(nome_arq) == 0);
	arq = fopen(nome_arq, modo);
	if (arq == NULL) {
		printf("Erro: falha na abertura de arquivo\n");
		abort();
	}

	return arq;
}

char leOpcao() {
	char opcao;

	do {
		opcao = getchar();
	} while (opcao == '\n' || opcao == '\t' || opcao == '\r' || opcao == ' ');

	return opcao;
}

int main() {
	FILE *arq = NULL, *arq2 = NULL;
	APE M;
	Lexer L;
	char *cadeia, token, continua = 's', reutilizaAPE = 'n', reutilizaLexer =
			'n', imprime;
	int fimCadeia;

	while (continua == 's' || continua == 'S') {
		if (reutilizaLexer != 's' && reutilizaLexer != 'S') {
			printf("Digite o nome do arquivo com as "
					"especificações do analisador léxico: ");
			arq = abreArquivo("r");
			criaLexer(arq, &L);
			fclose(arq);

			printf("Deseja gerar um arquivo com a "
					"descrição do analisador léxico criado?[s/n] ");
			imprime = leOpcao();
			if (imprime == 's' || imprime == 'S') {
				printf("Digite o nome do arquivo a ser gerado: ");
				arq = abreArquivo("w");
				imprimeLexer(arq, &L);
				fclose(arq);
			}
		}

		if (reutilizaAPE != 's' && reutilizaAPE != 'S') {
			printf("Digite o nome do arquivo com as "
					"especificaçoes do autômato de pilha: ");
			arq = abreArquivo("r");
			criaAPE(arq, &M);
			fclose(arq);

			printf("Deseja gerar um arquivo com a "
					"descrição do autômato de pilha criado?[s/n] ");
			imprime = leOpcao();
			if (imprime == 's' || imprime == 'S') {
				printf("Digite o nome do arquivo a ser gerado: ");
				arq = abreArquivo("w");
				imprimeAPE(arq, &M);
				fclose(arq);
			}
		}

		printf("Digite o nome do arquivo contendo "
				"a cadeia a ser analisada: ");
		arq2 = abreArquivo("r");

		printf("Deseja gerar um arquivo com os passos "
				"executados durante a análise da cadeia?[s/n] ");
		imprime = leOpcao();
		if (imprime == 's' || imprime == 'S') {
			printf("Digite o nome do arquivo no qual armazenar os "
					"passos da análise: ");
			arq = abreArquivo("w");
		}

		while (!feof(arq2)) {
			cadeia = leCadeia(arq2);
			if (imprime == 's' || imprime == 'S') {
				fprintf(arq, "Cadeia: %s\n\n", cadeia);
				fprintf(arq, "%10s%10s%10s%10s%10s%10s%10s%10s", "Submaq.",
						"Estado", "final", "extr.", "token", "chamada",
						"devol.", "pilha");
			}
			inicializaLexer(cadeia, &L);
			inicializaAPE(&M);
			token = 0;
			fimCadeia = FALSE;

			while (token != -1) {
				if (imprime == 's' || imprime == 'S') {
					fprintf(arq, "\n%10c%10s", M.submaquinaAtual->nome,
							M.submaquinaAtual->AF.estadoAtual->nome);
					if (M.submaquinaAtual->AF.estadoAtual->final == TRUE) {
						fprintf(arq, "%10s", "sim");
					} else {
						fprintf(arq, "%10s", "nao");
					}
				}

				if (token == 0 && fimCadeia == FALSE) {
					extraiToken(&L);

					if (imprime == 's' || imprime == 'S') {
						fprintf(arq, "%10s", "sim");
					}
				} else if (imprime == 's' || imprime == 'S') {
					fprintf(arq, "%10s", "nao");
				}

				token = passaToken(&L);
				if (token == 0) {
					fimCadeia = TRUE;
				}

				recebeTokenAPE(token, &M);
				token = analisaToken(&M, imprime, arq);
				if (token > 0) {
					recebeTokenLexer(token, &L);
				}
			}

			if (aceita(&M) == TRUE) {
				if (imprime == 's' || imprime == 'S') {
					fprintf(arq, "\n\nCadeia aceita\n\n");
				}
				printf("\nCadeia aceita");
			} else {
				if (imprime == 's' || imprime == 'S') {
					fprintf(arq, "\n\nCadeia rejeitada\n\n");
				}
				printf("\nCadeia rejeitada");
			}

			if (imprime == 's' || imprime == 'S') {
			}
			free(cadeia);
		}

		if (imprime == 's' || imprime == 'S') {
			fclose(arq);
		}
		if (arq2 != NULL) {
			fclose(arq2);
		}

		printf("\n\nDeseja realizar mais um teste?[s/n] ");
		continua = leOpcao();
		if (continua == 's' || continua == 'S') {
			printf("Deseja reutilizar o analisador léxico?[s/n] ");
			reutilizaLexer = leOpcao();
			printf("Deseja reutilizar o autômato de pilha?[s/n] ");
			reutilizaAPE = leOpcao();
		}
	}

	return 0;
}
